﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace game2048
{
    public class Game2048
    {
        //调整此数可以适应不同的矩阵棋盘,就可以扩充玩法
        public static int g_line = 4;
        //维护一个静态数组用于保存或计算游戏的状态
        public static int[,] g_game_array;
        //静态实例
        private static Game2048 gameIns=null;
        //分数
        public static int g_score=0;
        //是否添加棋子
        private static bool g_add = false;
        //赢了
        public static bool g_win = false;
        //输了
        public static bool g_lose = false;
        /// <summary>
        /// 单例模式
        /// </summary>
        private Game2048()
        {

        }
        /// <summary>
        /// 取得实例
        /// </summary>
        /// <returns></returns>
        public static Game2048 GetInstance()
        {
            if (gameIns == null)
                gameIns = new Game2048();
            return gameIns;
        }
        /// <summary>
        /// 添加棋子
        /// </summary>
        /// <returns></returns>
        private static bool AddBoard()
        {
            if (gameIns != null)
            {
                //可以调节2，4出现频率
                int[] choice = { 4, 2, 4, 2, 4, 2, 2, 2 };
                //随机数取棋盘坐标
                Random ra = new Random();
                int x = ra.Next(0, g_line);
                int y = ra.Next(0, g_line);
                int ch = ra.Next(0, 7);
                
                while(g_game_array[x,y]!=0)
                {
                    //位置已有数据，重新选取
                    x = ra.Next(0, g_line);
                    y = ra.Next(0, g_line);
                }
                //放入棋盘
                g_game_array[x, y] = choice[ch];
                g_add = false;
                
            }
            return true;
        }
        /// <summary>
        /// 重启游戏
        /// </summary>
        public static void Restart()
        {
            if (gameIns != null)
            {
                //初始化分数
                g_score = 0;
                //是否添加棋子
                g_add = false;
                //初始化输赢状态
                g_win = false;
                g_lose = false;
                g_game_array = new int[g_line, g_line];
                for(int i=0;i< g_line; i++)
                {
                    for (int j = 0; j < g_line; j++)
                        //初始化数组
                        g_game_array[i, j] = 0;
                }
                //添加两个棋子
                AddBoard();
                AddBoard();
            }
        }
        /// <summary>
        /// 按下上键
        /// </summary>
        public static void Up()
        {
            if (gameIns != null)
            {
                for(int i=0;i<g_line;i++)
                {
                    for(int t=0;t< g_line; t++)
                    {
                        for(int j=0;j< g_line - 1;j++)
                        {
                            //上移时，如果上面为零，下面不为零，两数交换
                            if(g_game_array[j,i]==0)
                            {
                                //发生了移动
                                if (g_game_array[j+1,i]!=0)
                                {
                                    g_add = true;
                                }
                                int temp = g_game_array[j, i];
                                g_game_array[j, i] = g_game_array[j + 1, i];
                                g_game_array[j + 1, i] = temp;
                            }
                        }
                    }
                    //合并相同的数
                    for(int j=0;j< g_line - 1;j++)
                    {
                        //2 2 2 2->4 0 2 2->4 0 4 0
                        //2 2 2 0->4 0 2 0
                        if(g_game_array[j,i]==g_game_array[j+1,i])
                        {
                            //发生了合并
                            if (g_game_array[j,i]!=0)
                            {
                                g_add = true;
                            }
                            //两数相加
                            g_game_array[j, i] = g_game_array[j, i] * 2;
                            //计分
                            g_score = g_game_array[j, i] + g_score;
                            g_game_array[j + 1, i] = 0;
                        }
                    }
                    //再次移动0元素
                    for(int t=0;t< g_line; t++)
                    {
                        for(int j=0;j<g_line-1;j++)
                        {
                            //0 2 0 2->2 2 0 0
                            if(g_game_array[j,i]==0)
                            {
                                int temp = g_game_array[j, i];
                                g_game_array[j, i] = g_game_array[j + 1, i];
                                g_game_array[j + 1, i] = temp;
                            }
                        }
                    }
                }
                if(Lost()||WIN())
                {
                    g_win = WIN();
                    g_lose = Lost();
                }
                else
                {
                    if(g_add)
                    {
                        //添加棋子
                        AddBoard();
                        g_add = false;
                    }
                }
            }
        }
        /// <summary>
        /// 按下下键
        /// </summary>
        public static void Down()
        {
            if (gameIns != null)
            {
                for (int i = 0; i < g_line; i++)
                {
                    for (int t = g_line; t > 0; t--)
                    {
                        for (int j = g_line - 1; j >0 ; j--)
                        {
                            //下移时，如果下面为零，上面不为零，两数交换
                            if (g_game_array[j, i] == 0)
                            {
                                //发生了移动
                                if (g_game_array[j - 1, i] != 0)
                                {
                                    g_add = true;
                                }
                                int temp = g_game_array[j, i];
                                g_game_array[j, i] = g_game_array[j - 1, i];
                                g_game_array[j - 1, i] = temp;
                            }
                        }
                    }
                    //合并相同的数
                    for (int j = g_line - 1; j >0 ; j--)
                    {
                        //2 2 2 2->4 0 2 2->4 0 4 0
                        //2 2 2 0->4 0 2 0
                        if (g_game_array[j, i] == g_game_array[j - 1, i])
                        {
                            //发生了合并
                            if (g_game_array[j, i] != 0)
                            {
                                g_add = true;
                            }
                            //两数相加
                            g_game_array[j, i] = g_game_array[j, i] * 2;
                            //计分
                            g_score = g_game_array[j, i] + g_score;
                            g_game_array[j - 1, i] = 0;
                        }
                    }
                    //再次移动0元素
                    for (int t = g_line; t >0 ; t--)
                    {
                        for (int j = g_line - 1; j >0 ; j--)
                        {
                            //0 2 0 2->2 2 0 0
                            if (g_game_array[j, i] == 0)
                            {
                                int temp = g_game_array[j, i];
                                g_game_array[j, i] = g_game_array[j - 1, i];
                                g_game_array[j - 1, i] = temp;
                            }
                        }
                    }
                }
                if (Lost() || WIN())
                {
                    g_win = WIN();
                    g_lose = Lost();
                }
                else
                {
                    if (g_add)
                    {
                        //添加棋子
                        AddBoard();
                        g_add = false;
                    }
                }
            }
        }
        /// <summary>
        /// 按下左键
        /// </summary>
        public static void Left()
        {
            if (gameIns != null)
            {
                for (int j = 0; j < g_line; j++)
                {
                    for (int t = 0; t < g_line; t++)
                    {
                        for (int i = 0; i < g_line - 1; i++)
                        {
                            //左移时，如果左面为零，右面不为零，两数交换
                            if (g_game_array[j, i] == 0)
                            {
                                //发生了移动
                                if (g_game_array[j, i+1] != 0)
                                {
                                    g_add = true;
                                }
                                int temp = g_game_array[j, i];
                                g_game_array[j, i] = g_game_array[j, i+1];
                                g_game_array[j, i+1] = temp;
                            }
                        }
                    }
                    //合并相同的数
                    for (int i = 0; i< g_line - 1; i++)
                    {
                        //2 2 2 2->4 0 2 2->4 0 4 0
                        //2 2 2 0->4 0 2 0
                        if (g_game_array[j, i] == g_game_array[j , i+1])
                        {
                            //发生了合并
                            if (g_game_array[j, i] != 0)
                            {
                                g_add = true;
                            }
                            //两数相加
                            g_game_array[j, i] = g_game_array[j, i] * 2;
                            //计分
                            g_score = g_game_array[j, i] + g_score;
                            g_game_array[j, i+1] = 0;
                        }
                    }
                    //再次移动0元素
                    for (int t = 0; t < g_line; t++)
                    {
                        for (int i = 0; i < g_line - 1; i++)
                        {
                            //0 2 0 2->2 2 0 0
                            if (g_game_array[j, i] == 0)
                            {
                                int temp = g_game_array[j, i];
                                g_game_array[j, i] = g_game_array[j , i+1];
                                g_game_array[j , i+1] = temp;
                            }
                        }
                    }
                }
                if (Lost() || WIN())
                {
                    g_win = WIN();
                    g_lose = Lost();
                }
                else
                {
                    if (g_add)
                    {
                        //添加棋子
                        AddBoard();
                        g_add = false;
                    }
                }
            }
        }
        /// <summary>
        /// 按下右键
        /// </summary>
        public static void Right()
        {
            if (gameIns != null)
            {
                for (int j = 0; j < g_line; j++)
                {
                    for (int t = g_line; t >0; t--)
                    {
                        for (int i = g_line -1; i >0; i--)
                        {
                            //左移时，如果右面为零，左面不为零，两数交换
                            if (g_game_array[j, i] == 0)
                            {
                                //发生了移动
                                if (g_game_array[j, i - 1] != 0)
                                {
                                    g_add = true;
                                }
                                int temp = g_game_array[j, i];
                                g_game_array[j, i] = g_game_array[j, i - 1];
                                g_game_array[j, i - 1] = temp;
                            }
                        }
                    }
                    //合并相同的数
                    for (int i = g_line - 1; i >0; i--)
                    {
                        //2 2 2 2->4 0 2 2->4 0 4 0
                        //2 2 2 0->4 0 2 0
                        if (g_game_array[j, i] == g_game_array[j, i - 1])
                        {
                            //发生了合并
                            if (g_game_array[j, i] != 0)
                            {
                                g_add = true;
                            }
                            //两数相加
                            g_game_array[j, i] = g_game_array[j, i] * 2;
                            //计分
                            g_score = g_game_array[j, i] + g_score;
                            g_game_array[j, i - 1] = 0;
                        }
                    }
                    //再次移动0元素
                    for (int t = g_line; t >0; t--)
                    {
                        for (int i = g_line - 1; i >0 ; i--)
                        {
                            //0 2 0 2->2 2 0 0
                            if (g_game_array[j, i] == 0)
                            {
                                int temp = g_game_array[j, i];
                                g_game_array[j, i] = g_game_array[j, i - 1];
                                g_game_array[j, i - 1] = temp;
                            }
                        }
                    }
                }
                if (Lost() || WIN())
                {
                    g_win = WIN();
                    g_lose = Lost();
                }
                else
                {
                    if (g_add)
                    {
                        //添加棋子
                        AddBoard();
                        g_add = false;
                    }
                }
            }
        }
        /// <summary>
        /// 游戏赢了
        /// </summary>
        private static bool WIN()
        {
            if (gameIns != null)
            {
                for(int i=0;i<g_line;i++)
                {
                    for(int j=0;j<g_line;++j)
                    {
                        //出现2048，即为赢
                        if (g_game_array[i, j] == 2048)
                            return true;
                    }
                }
            }
            return false;
        }
        /// <summary>
        /// 游戏输了
        /// </summary>
        private static bool Lost()
        {
            if (gameIns != null)
            {
                bool lose = true;
                for(int i=0;i<g_line;i++)
                {
                    for(int j=0;j<g_line;j++)
                    {
                        //有0，未结束
                        if(g_game_array[i,j]==0)
                        {
                            lose = false;
                            return false;
                        }
                    }
                }
                for(int i=0;i<g_line-1;i++)
                {
                    for(int j=0;j<g_line-1;j++)
                    {
                        //横竖相邻元素相等未结束
                        if (g_game_array[i, j] == g_game_array[i, j + 1] && g_game_array[i, j] != 0)
                            return false;
                        if (g_game_array[j, i] == g_game_array[j + 1, i] && g_game_array[j, i] != 0)
                            return false;
                    }
                }
                if (lose)
                    return true;
            }
            return false;
        }
    }
}
